﻿namespace Hotel.Module.Infrastructure
{
    using System;
    using System.Transactions;

    ///TODO: Add description there
    ///
    public abstract class DomainControllerBase : IDisposable
    {
        public DomainControllerBase(ITransaction transaction, bool autoComplete)
        {
            m_transaction = transaction;
            m_IsExternal = (m_transaction != null);
        }

        public DomainControllerBase(IServiceProvider provider, ITransaction transaction, bool autoComplete)
        {
            m_transaction = transaction;
            m_IsExternal = (m_transaction != null);
            ServiceProvider = provider;

            if (provider != null)
            {
                Storage = provider.GetService(typeof(IStorageController)) as IStorageController;
            }
        }

        public bool InTransaction { get { return m_transaction != null & Transaction.Current != null; } }

        /// <summary>
        /// Provides access to entity's storage
        /// </summary>
        public IStorageController Storage { get; set; }

        /// <summary>
        /// Provides functionality to create any service or logic controller
        /// </summary>
        public IServiceProvider ServiceProvider { get; set; }

        /// <summary>
        /// Auto complete transaction if controller is destroy
        /// </summary>
        public bool AutoComplete { get; private set; }

        #region IDisposable members

        protected abstract void Dispose(bool disposeManaged);

        public void Dispose()
        {
            if (!m_IsExternal & (AutoComplete & InTransaction))
            {
                m_transaction.Commit();
            }

            if (!m_IsExternal & (AutoComplete & !InTransaction))
            {
                m_transaction.Rollback();
            }

            if (m_transaction != null & !m_IsExternal)
                m_transaction.Dispose();

            Storage = null;

            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        ~DomainControllerBase()
        {
            Dispose(false);
        }

        #region Private logic

        protected void InitializeTransaction(ITransactionCreator creator)
        {
            if (creator == null)
                throw new ArgumentNullException("creator");

            if (InTransaction)
                throw new InvalidOperationException("Can't to create transaction until transaction is running");

            m_IsExternal = false;
            m_transaction = creator.Create();

            if (m_transaction == null)
                throw new InvalidOperationException("Transaction object creation fails");

        }

        protected void Complete(bool hardComplete =false)
        {
            if ((!m_IsExternal | hardComplete) & (InTransaction))
            {
                m_transaction.Commit();
                m_transaction = null;
            }
        }

        #endregion

        private ITransaction m_transaction;
        private bool m_IsExternal = false;
    }
}
